/*  
 Copyright 2010 The 'Tribe.Blog' development team  
 (http://tribecache.codeplex.com/team/view)

 This library is licensed under the Ms-PL Microsoft Public License.  You should 
 have received a copy of the license along with the source code.  If not, an online copy
 of the license can be found at http://tribecache.codeplex.com/license.
*/

using System;
using System.Collections.Generic;
using System.Threading;
using Tribe.Cache.Storage;
using Tribe.Cache.Threading;

namespace Tribe.Cache.Helpers
{
    internal static class CacheTableHelper
    {
        /// <summary>
        /// Gets an item from the cache based on the entryId
        /// </summary>
        /// <param name="source">The cache table</param>
        /// <param name="entryId">The identifier that will be used to retrieve the object from the cache table</param>
        /// <param name="hasExpired"></param>
        /// <returns>CacheTableItem</returns>
        public static CacheTableItem Get(this CacheTable source, string entryId, out bool hasExpired)
        {
            try
            {

                CacheTableItem tableItem = source[entryId];
                tableItem.IsDirty = true;
                hasExpired = HasItemExpired(source, entryId);

                if(hasExpired)
                {
                    Delete(source, entryId);
                    return null;
                }

                return tableItem;
            }
            catch (KeyNotFoundException)
            {
                hasExpired = true;
                return null;
            }
        }

        /// <summary>
        /// Gets an item from the cache table based on the entryId - Resets the DateOfExpiration to Now plus the origional cache duration
        /// </summary>
        /// <param name="source">The cache table</param>
        /// <param name="entryId">The identifier that will be used to retrieve the object from the cache table</param>
        /// <param name="resetDateOfExpiration">Resets the date of expiration to now</param>
        /// <param name="hasExpired"></param>
        /// <returns>CacheTableItem</returns>
        public static CacheTableItem Get(this CacheTable source, string entryId, bool resetDateOfExpiration, out bool hasExpired)
        {
            try
            {
                CacheTableItem tableItem = source[entryId];
                hasExpired = HasItemExpired(source, entryId);
                
                if(hasExpired)
                {
                    Delete(source,entryId);
                    return null;
                }
                //Remove the old key as now the DateOfExpiration needs to be reset to now
                source.Remove(entryId);
                //Reset the DateOfExpirationToNow
                tableItem.DateOfExpiration = DateTime.Now.Add(tableItem.SpanToCache);
                //Re-add the cacheTableItem to the cache dictionary
                source.Add(entryId, tableItem);
                //Set the is dirty flag as this is still an old instace of the object
                tableItem.IsDirty = true;

                return tableItem;

            }
            catch (KeyNotFoundException)
            {
                hasExpired = false;
                return null;
            }
        }

        /// <summary>
        /// Adds an item to the cache table
        /// </summary>
        /// <typeparam name="T">Return type - will be inferred from the return type of the delegates encapsulated method</typeparam>
        /// <param name="source">The cache table</param>
        /// <param name="item">() => class.Method(param) </param>
        /// <param name="spanToCache">Timespan to cache the item for</param>
        /// <param name="cacheId">The identifier that will be used to retrieve the object from the cache table</param>
        /// <returns>CacheTableItem</returns>
        public static CacheTableItem Put<T>(this CacheTable source, Func<T> item, TimeSpan spanToCache, string cacheId)
        {
            CacheTableItem cacheTableItem = new CacheTableItem
            {
                DateOfExpiration = DateTime.Now.Add(spanToCache),
                EntryId = cacheId,
                Item = item(),
                IsDirty = false,
                SpanToCache = spanToCache
            };

            source.Add(cacheTableItem.EntryId, cacheTableItem);
            return cacheTableItem;

        }
        /// <summary>
        /// Removes an item from the cache
        /// </summary>
        /// <param name="source">The cache table</param>
        /// <param name="cacheId">The identifier that will be used to remove the object from the cache table</param>
        public static void Delete(this CacheTable source, string cacheId)
        {
            source.Remove(cacheId);
        }
        /// <summary>
        /// Clears all items in the cache table
        /// </summary>
        /// <param name="source">The cache table</param>
        public static void ClearCache(this IDictionary<string, CacheTableItem> source)
        {
            source.Clear();
        }
        /// <summary>
        /// Counts all the items in the cache table
        /// </summary>
        /// <param name="source">The cache table</param>
        /// <returns>int</returns>
        public static int Count(this CacheTable source)
        {
            return source.Count;
        }
        /// <summary>
        /// Checks to see if the CacheTableItem in the cache table has expired
        /// </summary>
        /// <param name="source">The cache table</param>
        /// <param name="cacheKey"></param>
        /// <returns>bool</returns>
        public static bool HasItemExpired(this CacheTable source, string cacheKey)
        {
            return source[cacheKey].DateOfExpiration < DateTime.Now;
        }
        /// <summary>
        /// Clears out all items in the cache table that have expired
        /// </summary>
        /// <param name="source">The cache table</param>
        public static void ClearExpired(this CacheTable source)
        {
            string[] keys = new string[source.Count];
            
            source.Keys.CopyTo(keys,0);
            
            foreach (string cacheKey in keys)
            {
                if (source.HasItemExpired(cacheKey))
                {
                    source.Remove(cacheKey);
                }
            }
        }
    }
}